package com.njcb.ams.support.trade;

import java.util.Arrays;
import java.util.UUID;

import com.njcb.ams.pojo.enumvalue.TransStatusCode;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.njcb.ams.bootconfig.AmsProperties;
import com.njcb.ams.repository.entity.SysTradeLog;
import com.njcb.ams.portal.SysBaseDefine;
import com.njcb.ams.factory.comm.DataBus;
import com.njcb.ams.service.LogManageService;
import com.njcb.ams.support.annotation.Trader;
import com.njcb.ams.support.annotation.enums.MonitorLevel;
import com.njcb.ams.support.comm.SequenceService;
import com.njcb.ams.support.exception.AppException;
import com.njcb.ams.support.exception.BusinessException;
import com.njcb.ams.support.exception.ExceptionCode;
import com.njcb.ams.support.exception.ExceptionUtil;
import com.njcb.ams.support.trade.filter.TradeFilterChain;
import com.njcb.ams.util.AmsDateUtils;
import com.njcb.ams.util.AmsUtils;
import com.njcb.ams.util.SysInfoUtils;

/**
 * 应用交易层切面处理切面
 *
 * @author liuyanlong
 */
@Component
@Aspect
@Lazy(false)
@Order(0)
public class TradeAspect {
    private static final Logger logger = LoggerFactory.getLogger(TradeAspect.class);
    @Autowired
    private LogManageService logManageService;

    @Autowired
    private AmsProperties amsProperties;

    @Around(value = "@within(com.njcb.ams.support.annotation.Interaction) && @annotation(anm)")
    public Object aroundMethod(ProceedingJoinPoint pjd, Trader anm) throws Throwable {
        boolean isLog = logger.isInfoEnabled();
        if (isLog) {
            logger.info("交易[{}]流水号[{}]\n参数为:[{}]", anm.tradeCode(), TradeUtil.getTransSeq(), Arrays.toString(pjd.getArgs()));
        }
        MonitorLevel monitorLevel = anm.monitorLevel();
        //无监管模式下直接调用
        if (MonitorLevel.NO_MONITOR == monitorLevel) {
            return pjd.proceed();
        }

        long startTime = System.currentTimeMillis();
        DataBus.setTrader(anm);
        //初始化SysTradeLog
        SysTradeLog tradeLog = initSysTradeLog(anm);
        tradeLog.setTimeStamp(startTime);
        setTradeLogValue(tradeLog, anm);
        if (anm.synLog()) {
            logManageService.synAddLog(tradeLog);
        }

        Object result = null;
        try {
            TradeFilterChain filterChain = new TradeFilterChain(pjd, anm, TradeService.getFilters());
            result = filterChain.doFilter(filterChain);
            tradeLog.setTransStatus(TransStatusCode.SUCC.getCode());
            tradeLog.setRetMsg(TransStatusCode.SUCC.getDesc());
        } catch (Throwable e) {
            if (null != e.getCause()) {
                e = e.getCause();
            }
            tradeLog.setTransStatus(TransStatusCode.FAIL.getCode());
            if (e instanceof AppException) {
                AppException ae = (AppException) e;
                tradeLog.setRetCode(ae.getErrorCode());
                tradeLog.setRetMsg(ae.getMessage());
            } else if (e instanceof BusinessException) {
                BusinessException be = (BusinessException) e;
                tradeLog.setRetCode(be.getErrorCode());
                tradeLog.setRetMsg(be.getMessage());
            } else {
                //错误码 系统编码+两位模块代码+类型+错误码
                String defaultCode = SysInfoUtils.getSysId() + ExceptionUtil.EXCEPTION_MODEL_DEFAULT + ExceptionUtil.EXCEPTION_TYPE_T + ExceptionCode.UNDEFINED_EXCEPTION;
                tradeLog.setRetCode(defaultCode);
                tradeLog.setRetMsg("[" + e.getClass().getSimpleName() + "]" + e.getMessage());
                tradeLog.setTransStatus(TransStatusCode.EROR.getCode());
            }
            logger.error("\n业务异常:{},异常种类{},调用信息:{}", e.getMessage(), e.getClass().getSimpleName(), ExceptionUtil.getStackTraceMsg(e));
            throw e;
        } finally {
            long useTime = System.currentTimeMillis() - startTime;
            tradeLog.setUseTime(useTime);
            tradeLogFinally(tradeLog, anm);
            if (isLog) {
                String msg = TransStatusCode.SUCC.getCode().equals(tradeLog.getTransStatus()) ? "交易成功" : "交易失败" + tradeLog.getRetMsg();
                logger.info("\n交易[{}]耗时[{}]毫秒，流水号[{}]\n{}", anm.tradeCode(), useTime, tradeLog.getReqSeq(), msg);
            }
            //清除异常堆栈输出标准  参见ExceptionUtil.printStackTrace()
            DataBus.removeAttribute(ExceptionUtil.EXCEPTION_STACK_TRACE);
        }
        if (isLog) {
            logger.info("交易[{}]流水号[{}]的输出为:\n[{}]", anm.tradeCode(), TradeUtil.getTransSeq(), null == result ? "void" : result.toString());
        }
        return result;
    }

    private SysTradeLog initSysTradeLog(Trader anm) {
        SysTradeLog tradeLog = new SysTradeLog();
        tradeLog.setTradeCode(anm.tradeCode());
        tradeLog.setTradeName(anm.tradeName());
        tradeLog.setTradeType(SysTradeLog.TRADETYPE_10);
        tradeLog.setTransStatus(TransStatusCode.BEING.getCode());
        tradeLog.setTradeNode(SysBaseDefine.TRADE_NODE);
        tradeLog.setAppVersion(SysBaseDefine.APP_VERSION);
        tradeLog.setRetCode("0000");
        tradeLog.setRetMsg(TransStatusCode.BEING.getDesc());
        TradeUtil.setTradeCode(tradeLog.getTradeCode());
        TradeUtil.setTradeName(tradeLog.getTradeName());
        if (amsProperties.getDbEnable()) {
            TradeUtil.setTransSeq(SequenceService.getInstance().genSeqStr("TRANSSEQ"));
        } else {
            TradeUtil.setTransSeq(UUID.randomUUID().toString());
        }
        if (AmsUtils.isNotNull(TradeUtil.getReqSeq())) {
            TradeUtil.setTransSeq(TradeUtil.getReqSeq());
        }else{
            TradeUtil.setReqSeq(TradeUtil.getTransSeq());
        }
        return tradeLog;
    }

    private void tradeLogFinally(SysTradeLog tradeLog, Trader anm) {
        tradeLog.setBusiSign(TradeUtil.getBusiSign());
        tradeLog.setRemark(TradeUtil.getRemark());
        /**
         * mod by liuyanlong at 20201208
         * 支持日志同步写入
         */
        if (anm.synLog()) {
            logManageService.updateLog(tradeLog);
        } else {
            logManageService.asynAddLog(tradeLog);
        }
    }

    private void setTradeLogValue(SysTradeLog tradeLog, Trader anm) {
        tradeLog.setBusiSign(TradeUtil.getBusiSign());
        tradeLog.setRemark(TradeUtil.getRemark());
        tradeLog.setTransSeq(TradeUtil.getTransSeq());
        tradeLog.setGlobalSeq(TradeUtil.getGlobalSeq());
        tradeLog.setReqSeq(TradeUtil.getReqSeq());
        tradeLog.setReqDate(AmsDateUtils.getCurrentDate8());
        tradeLog.setReqTime(AmsDateUtils.getCurrentTime6());
//			mod by liuyanlong at 20180926  暂不清理否则无法在交易外层传递参数
//			GlobalInfo.clearAttributes();
        DataBus.setAttribute(SysBaseDefine.GLOBALINFO_SYSTRADELOG, tradeLog);
    }
}
